/**
* \file main.c
* \brief mbootload的主程序
*	1.mbootload:
*							 1.实现boot_drv中的接口函数
*							 2.定义相关地址(下载,执行,标志等)
*   
*	2.app:
############对于STM32F103和STM32F429
*							 1.设置app程序起始地址,存储空间大小(MDK设置即可)
*							 2.设置中断向量表偏移量(SystemInit函数内设置)
*							 3.设置编译后运行fromelf.exe,生成bin文件(MDK设置即可)
*                fromelf.exe --bin -o "$L@L.bin" "#L"
############对于NXP RT1052

############对于stm32f030--2020-05-28
*              1.设置app程序起始地址,ram起始地址。
*              2.重映射sram首地址到0x00000000,同时读取中断向量表到sram 0x20000000地址
*							 3.设置编译后运行fromelf.exe,生成bin文件(MDK设置即可)
*                fromelf.exe --bin -o "$L@L.bin" "#L"
*
* \author mirlee
* \version 0.2
* \date 2019-08-02 
*/
#include "boot_drv.h"
#include "ymodem.h"
#include "string.h"
void mbl_upgrade_menu(void);
int mbl_check_upgrade_flag(void);
void mbl_clear_upgrade_flag(void);
int mbl_check_stack_head(unsigned long execAdr);
void mbl_execute_app(volatile unsigned long appAdr);
void mbl_app_dowload(volatile unsigned long appAdr);
int mbl_check_key(void);

extern void System(void);
typedef void (*bootApp)(void);
bootApp bootAppM;

#ifndef STM32F030x
static __inline void __set_MSP(unsigned long topOfMainStack)
{
  register unsigned long __regMainStackPointer     __asm("msp");
  __regMainStackPointer = topOfMainStack;
}
#endif

int main()
{
	__disable_irq();
#if (NXPRT1052x)
	System();
#endif

	/*检查升级标志位*/
	if(mbl_check_upgrade_flag()==0)
	{
bml_upgrade_menu:
		/*升级菜单*/
		mbl_upgrade_menu();
	}
	else
	{
		/*执行用户程序*/
		mbl_execute_app(MBL_APP_EXEC_ADR);
	}
	while(1)
	{
		mbl_print_str("no program, enter 0 to download\r\n");
		if(mbl_check_key()=='0')
		{
			goto bml_upgrade_menu;
		}
	}	
}

void mbl_upgrade_menu(void)
{
	int key=0;

	while(1)
	{
		mbl_print_str("dowload bin file enter 1 \r\n"
									"execute app      enter 2 \r\n"
									"-------------------------\r\n");
		key=mbl_check_key();
		if(key=='1')
		{
			/*接收bin*/
			mbl_app_dowload(MBL_APP_WR_ADR);
		}
		else if(key=='2')
		{
			/*擦除升级标志位*/
			mbl_clear_upgrade_flag();
			/*执行用户程序*/
			mbl_execute_app(MBL_APP_EXEC_ADR);
		}
	}
}

void mbl_execute_app(volatile unsigned long appAdr)
{
	unsigned long jumpaddr;
	//程序首个字里存的内容为栈顶地址
	if(mbl_check_stack_head(appAdr)==0)
	{
		jumpaddr = (*(volatile unsigned long*)(appAdr+4));
		bootAppM = (bootApp)jumpaddr;
		__set_MSP(*(volatile unsigned long*)appAdr);
		bootAppM();
	}
}
/**
 * @brief mbl_check_key
 * @note 阻塞方式检测输入,
 * @param 
 * @retval -1,error
 */
int mbl_check_key(void)
{
	unsigned char key=0;
	while(1)
	{
		mbl_recv_byte(&key,100);
		if(key>0)
			break;
	}
	return key;
}

void mbl_app_dowload(volatile unsigned long appAdr)
{
	long Size = 0;
	mbl_print_str("\r\n Please transmit the bin with Ymodem \r\n");
	mbl_flash_lock_or(0);
	Size = Ymodem_Receive(MBL_APP_WR_ADR);
	
	if (Size > 0)
	{
		mbl_print_str("cmpleted!\r\n  \
									 ---------\r\n name: ");
		mbl_print_str((char *)file_name);
		mbl_clear_upgrade_flag();               //擦除IAP升级标志位存放页
	}
	else if (Size == MBL_YMODEM_ABORTED_ERROR)
	{
		mbl_print_str("aborted by user.\r\n");
	}
	else if(Size==MBL_FLASH_ERASE_ERROR)
	{
		mbl_print_str("flash erase error\r\n");
	}
	else if(Size==MBL_FLASH_WRITE_ERROR)
	{
		mbl_print_str("flash write error\r\n");
	}
	else
	{
		mbl_print_str("failed to receive\n\r");
	}
}

void mbl_print_str(char *str)
{
	while(1)
	{
		if(*str!='\0')
		{
			mbl_send_byte(*str);
			str++;
		}
		else
		{
			mbl_send_byte('\0');
			return;
		}
	}
}

int mbl_check_upgrade_flag(void)
{
#if (STM32F103x)||(STM32F429x||(STM32F030x))
	if(*((volatile unsigned long*)MBL_UP_FLAG_ADR)==MBL_UP_FLAG_VAL)
		return 0;
	else
		return -1;
#elif (NXPRT1052x)
	return 0;
#endif
}

void mbl_clear_upgrade_flag(void)
{
	mbl_flash_lock_or(0);
#if (STM32F103x)||(STM32F429x)
	mbl_flash_erase(MBL_UP_FLAG_ADR,4);
#elif (NXPRT1052x)
	return;
#endif
	mbl_flash_lock_or(1);
}

int mbl_check_stack_head(unsigned long execAdr)
{
#if (STM32F103x)||(STM32F429x)||(STM32F030x)
	if(((*(volatile unsigned long*)execAdr)& 0x2FFC0000) == 0x20000000)
		return 0;
	return -1;
#elif (NXPRT1052x)
	return 0;
#endif
}

